﻿using System;
using System.ComponentModel;
using System.Drawing;
using System.Globalization;
using System.IO;
using System.Runtime.InteropServices;
using Kyoh.Lib.Component.Globalization;
using Kyoh.Lib.Win32API;
using Kyoh.Lib.Win32API.Shell;
using Kyoh.Lib.WinForms;
using Microsoft.VisualBasic.FileIO;
using FileInfo = System.IO.FileInfo;
using System.Text.RegularExpressions;

namespace Kyoh.App.Renamer
{
    public partial class RenameEntryCollection
    {
        private sealed class RenameEntry
        {
            private bool? _userExcepted;

            [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
            public bool UserExcepted { get { return _userExcepted.Value; } }

            public bool UserHasExcepted { get { return _userExcepted.HasValue; } }

            [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
            public bool SystemExcepted { get; set; }

            [DisplayNameFromResource(typeof(Properties.Resources), "Excepted")]
            public bool Excepted
            {
                get { return UserHasExcepted ? _userExcepted.Value : SystemExcepted; }
                set { _userExcepted = value; }
            }

            [DisplayNameFromResource(typeof(Properties.Resources), "CurrentName")]
            public IconText CurrentName { get; private set; }

            [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
            public string UserNewName { get; private set; }
            public bool UserHasNewName { get { return !string.IsNullOrWhiteSpace(UserNewName); } }

            [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
            public string SystemNewName { get; set; }

            [DisplayNameFromResource(typeof(Properties.Resources), "NewName")]
            public string NewName
            {
                get { return UserHasNewName ? UserNewName : SystemNewName; }
                set { UserNewName = value; }
            }

            [DisplayNameFromResource(typeof(Properties.Resources), "Directory")]
            public string Directory { get; private set; }
            [DisplayNameFromResource(typeof(Properties.Resources), "Size")]
            public string Size { get; private set; }
            [DisplayNameFromResource(typeof(Properties.Resources), "TypeName")]
            public string TypeName { get; private set; }
            [DisplayNameFromResource(typeof(Properties.Resources), "Modification")]
            public string Modification { get; private set; }
            [DisplayNameFromResource(typeof(Properties.Resources), "Creation")]
            public string Creation { get; private set; }
            [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
            public string FullName { get; set; }
            [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
            public string Destination { get; set; }

            private bool isDirectory;
            private DateTime creationTime, modificationTime, accessTime;

            public RenameEntry(FileInfo file, IconManager iconManager)
            {
                Initialize(file, iconManager);
                Directory = file.DirectoryName;
                Size = file.Length.ToString("0,000 B", CultureInfo.CurrentUICulture);
                isDirectory = false;
                RenameHandler = FileSystem.MoveFile;
            }

            public RenameEntry(DirectoryInfo directory, IconManager iconManager)
            {
                Initialize(directory, iconManager);
                Directory = directory.Parent == null ? string.Empty : directory.Parent.FullName;
                Size = string.Empty;
                isDirectory = true;
                RenameHandler = FileSystem.MoveDirectory;
            }

            [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
            public Action<string, string, bool> RenameHandler { get; private set; }

            private void Initialize(FileSystemInfo fileSystem, IconManager iconManager)
            {
                var shFileInfo = new ShFileInfoW();
                NativeMethods.ShGetFileInfo(fileSystem.FullName, 0, ref shFileInfo,
                                            (uint) Marshal.SizeOf(shFileInfo),
                                            ShellFileInfoFlags.TypeName | ShellFileInfoFlags.Icon |
                                            ShellFileInfoFlags.SmallIcon);
                TypeName = shFileInfo.szTypeName;
                Image icon;
                try
                {
                    icon = iconManager.GetIcon(shFileInfo.hIcon);
                }
                catch
                {
                    icon = null;
                }
                if (shFileInfo.hIcon != IntPtr.Zero)
                    NativeMethods.DestroyIcon(shFileInfo.hIcon);

                CurrentName = new IconText {Text = fileSystem.Name, Icon = icon};
                FullName = fileSystem.FullName;
                SystemNewName = fileSystem.Name;

                modificationTime = fileSystem.LastWriteTime;
                creationTime = fileSystem.CreationTime;
                accessTime = fileSystem.LastAccessTime;
                Modification = modificationTime.ToString(CultureInfo.CurrentUICulture);
                Creation = creationTime.ToString(CultureInfo.CurrentUICulture);
            }

            internal string ReplaceSequence(Match match)
            {
                switch (match.Value[1])
                {
                    case 'f':
                        if (isDirectory)
                            return this.CurrentName.Text;
                        else
                            return Path.GetFileName(this.Directory);
                    case 'p':
                        return Path.GetFileName(this.Directory);
                    case 'x':
                        return Path.GetExtension(this.CurrentName.Text);
                    case 'a':
                        return accessTime.ToString(match.Groups["format"].Value);
                    case 'c':
                        return creationTime.ToString(match.Groups["format"].Value);
                    case 'm':
                        return modificationTime.ToString(match.Groups["format"].Value);
                    default:
                        return match.Value;
                }
            }
        }
    }
}